//
//  TimerTestViewController.m
//  iOSStudy
//
//  Created by Evan Xie on 8/27/15.
//  Copyright (c) 2015 Family Wings. All rights reserved.
//

#import "TimerTestViewController.h"
#import "FWLogger.h"


@interface TimerTestViewController ()
{
    NSTimer *_timerOnMainThread; // NSTimer can only work on main thread
    NSTimer *_timerOnSecondThreadWithRunloop;
    NSTimer *_timerOnSecondThreadWithoutRunloop; // NSTimer can not work on the second thread without runloop
    
    dispatch_source_t _timerSourceOnMainThread; // dispatch source timer can run on any queue
    dispatch_source_t _timerSourceOnSecondThread;
    
    UITextView *_logTextView;
}

@end

@implementation TimerTestViewController

- (void)dealloc
{
#if !OS_OBJECT_USE_OBJC
    dispatch_release(_timerSourceOnMainThread);
    dispatch_release(_timerSourceOnSecondThread);
#endif
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _logTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.contentSize.width, 300)];
    _logTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    _logTextView.backgroundColor = [UIColor blackColor];
    _logTextView.textColor = [UIColor whiteColor];
    self.tableView.tableFooterView = _logTextView;
}

- (IBAction)activeNSTimerOnMainthread:(id)sender
{
    UISwitch *switcher = (UISwitch *)sender;
    if (switcher.on) {
        _timerOnMainThread = [NSTimer scheduledTimerWithTimeInterval:3.0
                                                              target:self
                                                            selector:@selector(timerOnMainThreadFired:)
                                                            userInfo:nil
                                                             repeats:YES];
    } else {
        [_timerOnMainThread invalidate];
    }
}

- (IBAction)activeNSTimerOnSecondThreadWithRunloop:(id)sender
{
    UISwitch *switcher = (UISwitch *)sender;
    if (switcher.on) {
        [NSThread detachNewThreadSelector:@selector(startTimerOnSecondThreadWithRunLoop:) toTarget:self withObject:nil];
    } else {
        [_timerOnSecondThreadWithRunloop invalidate];
    }
}

- (IBAction)activeNSTimerOnSecondThreadWithoutRunloop:(id)sender
{
    UISwitch *switcher = (UISwitch *)sender;
    if (switcher.on) {
        [NSThread detachNewThreadSelector:@selector(startTimerOnSecondThreadWithoutRunLoop:) toTarget:self withObject:nil];
    } else {
        [_timerOnSecondThreadWithoutRunloop invalidate];
    }
}

- (IBAction)activeDispatchSourceTimerOnMainQueue:(id)sender
{
    UISwitch *switcher = (UISwitch *)sender;
    if (switcher.on) {
        _timerSourceOnMainThread = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
        
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 6*NSEC_PER_SEC);
        dispatch_source_set_timer(_timerSourceOnMainThread, time, 6*NSEC_PER_SEC, 0);
        dispatch_source_set_event_handler(_timerSourceOnMainThread, ^{
            [self displayLog:@"dispatch_source_t timer on [ main ] thread triggered."];
        });
        
        dispatch_source_set_cancel_handler(_timerSourceOnMainThread, ^{
            [self displayLog:@"dispatch_source_t timer on [ main ] thread cancelled."];
        });
        dispatch_resume(_timerSourceOnMainThread);
    } else {
        dispatch_source_cancel(_timerSourceOnMainThread);
    }
}

- (IBAction)activeDispatchSourceTimerOnSecondQueue:(id)sender
{
    UISwitch *switcher = (UISwitch *)sender;
    if (switcher.on) {
        _timerSourceOnSecondThread = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
        
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 4*NSEC_PER_SEC);
        dispatch_source_set_timer(_timerSourceOnSecondThread, time, 4*NSEC_PER_SEC, 0);
        dispatch_source_set_event_handler(_timerSourceOnSecondThread, ^{
            [self displayLog:@"dispatch_source_t timer on [ second ] thread triggered."];
        });
        
        dispatch_source_set_cancel_handler(_timerSourceOnSecondThread, ^{
            [self displayLog:@"dispatch_source_t timer on [ second ] thread cancelled."];
        });
        dispatch_resume(_timerSourceOnSecondThread);
    } else {
        dispatch_source_cancel(_timerSourceOnSecondThread);
    }
}

- (void)startTimerOnSecondThreadWithRunLoop:(NSThread *)thread
{
    // On the second thread, we need add the timer to the main runloop, the timer can still work normal
    _timerOnSecondThreadWithRunloop = [NSTimer timerWithTimeInterval:2.0
                                                              target:self
                                                            selector:@selector(timerOnSecondThreadWithRunloopFired:)
                                                            userInfo:nil
                                                             repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:_timerOnSecondThreadWithRunloop forMode:NSDefaultRunLoopMode];
}

- (void)startTimerOnSecondThreadWithoutRunLoop:(NSThread *)thread
{
    // On the second thread without adding timer to runloop, the timer can not work at all.
    _timerOnSecondThreadWithoutRunloop = [NSTimer scheduledTimerWithTimeInterval:4.0
                                                                          target:self
                                                                        selector:@selector(timerOnSecondThreadWithoutRunloopFired:)
                                                                        userInfo:nil
                                                                         repeats:YES];
}

- (void)timerOnMainThreadFired:(NSTimer *)timer
{
    [self displayLog:@"NSTimer on [ main ] thread triggered."];
}

- (void)timerOnSecondThreadWithRunloopFired:(NSTimer *)timer
{
    [self displayLog:@"NSTimer on [ second ] thread [with] runloop triggered."];
}

- (void)timerOnSecondThreadWithoutRunloopFired:(NSTimer *)timer
{
    [self displayLog:@"NSTimer on [ second ] thread [without] runloop triggered."];
}

- (void)displayLog:(NSString *)logMessage
{
    NSLog(@"%@\n", logMessage);
    [[FWLogger sharedLogger] logMessage:logMessage];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        _logTextView.text = [FWLogger sharedLogger].logMessagesInMemory;
    });
}

@end
